package cate.game.pvp.eliterace.timer;

import cate.game.event.eliterace.EliteRaceTimerEvent.EventType;
import cate.game.framework.Selector;
import cate.game.framework.timer.FIFOTimerTask;
import cate.game.pvp.eliterace.data.EliteRaceSpec;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.MoreObjects;
import easy.java.dev.note.NoteField;
import easy.java.time.DateTool;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.util.Objects;
import java.util.StringJoiner;
import java.util.function.Consumer;
import java.util.function.Function;

@ToString(exclude = {"settingsConsumer", "settingsFunction"})
public class EliteRaceTimerTask extends FIFOTimerTask {
    @NoteField(value = "接受一个setting 返回一个布尔值")
    private final Settings settings;

    @JsonIgnore
    private final Consumer<Settings> settingsConsumer;
    private final Function<Settings, Boolean> settingsFunction;

    public EliteRaceTimerTask(Settings settings,
                              Consumer<Settings> settingsConsumer,
                              Function<Settings, Boolean> settingsFunction) {
        super(settings.triggerTimeMs);
        this.settings = settings;
        this.settingsConsumer = settingsConsumer;
        this.settingsFunction = MoreObjects.firstNonNull(settingsFunction, s -> true);
    }

    @FunctionalInterface
    public interface Creator {
        EliteRaceTimerTask createTimerTask(Settings settings);
    }

    @FunctionalInterface
    public interface SettingsFunctionSelector extends
            Selector<Function<Settings, Boolean>, Settings> {
    }

    @NoArgsConstructor
    @Data
    public static class Settings {

        private EliteRaceSpec spec;

        private long triggerTimeMs;
        private EventType eventType = EventType.OPEN;

        public static Settings of(long triggerTimeMs, EventType eventType, EliteRaceSpec spec) {
            Settings settings = new Settings();
            settings.setSpec(spec);
            settings.setTriggerTimeMs(triggerTimeMs);
            settings.setEventType(eventType);
            return settings;
        }

        @Override
        public String toString() {
            return new StringJoiner(", ", Settings.class.getSimpleName() + "[", "]")
                    .add("spec=" + spec)
                    .add("triggerTimeMs=" + DateTool.instance().format(triggerTimeMs))
                    .add("eventType=" + eventType)
                    .toString();
        }
    }

    @Override
    public void run() {
        boolean apply = this.settingsFunction.apply(this.settings);
        if (apply && !isDone()) {
            setDone(true);
            if (Objects.nonNull(this.settingsConsumer)) {
                settingsConsumer.accept(settings);
            }
        }
    }
}
